package bb.lanxing.mvp.model;

import static bb.lanxing.model.database.RouteBook.TYPE_SOURCE_CREATE;
import static bb.lanxing.model.lushu.WayPoint.TYPE_CHECK_POINT;

import bb.lanxing.util.Log;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;

import org.json.JSONException;

import com.baidu.mapapi.model.LatLng;
import com.baidu.mapapi.model.LatLngBounds;
import com.besall.allbase.common.utils.LogUtils;
import com.github.mikephil.charting.utils.Utils;

import androidx.annotation.NonNull;

import bb.lanxing.lib.kt.model.geo.IGeoPoint;
import bb.lanxing.manager.SharedManager;
import bb.lanxing.model.database.RouteBook;
import bb.lanxing.model.database.RouteBookPoint;
import bb.lanxing.model.database.Waypoint;
import bb.lanxing.model.database.Workout;
import bb.lanxing.model.json.BiciLatlng;
import bb.lanxing.model.lushu.InMemoryRouteBookCacheStrategy;
import bb.lanxing.model.lushu.RouteBookCacheStrategy;
import bb.lanxing.model.lushu.WayPoint;
import bb.lanxing.mvp.model.i.RouteBookSourceModel;
import bb.lanxing.util.RouteBookUtil;

public abstract class AbstractRouteBookSourceModel implements RouteBookSourceModel {
	private final List<WayPoint> points;
	protected int sourceType;
	private RouteBookCacheStrategy cacheStrategy;
	private double distance;

	public AbstractRouteBookSourceModel(int sourceType) {
		this();
		this.sourceType = sourceType;
	}

	public AbstractRouteBookSourceModel() {
		this.points = new ArrayList<>();
		this.cacheStrategy = new InMemoryRouteBookCacheStrategy();
	}

	private static @NonNull ArrayList<Waypoint> getWaypoints(RouteBook routeBook, ArrayList<BiciLatlng> arrayList) {
		ArrayList<Waypoint> arrayList2 = new ArrayList<>();
		for (int i = 0; i < arrayList.size(); i++) {
			BiciLatlng biciLatlng2 = arrayList.get(i);
			Waypoint waypoint = new Waypoint();
			waypoint.setLushuId(routeBook.getId());
			waypoint.setLatitude(biciLatlng2.getLatitude());
			waypoint.setLongitude(biciLatlng2.getLongitude());
			waypoint.setTitle(biciLatlng2.getName());
			waypoint.setContent(biciLatlng2.getAddress());
			waypoint.setImage(biciLatlng2.getImage());
			waypoint.setType(biciLatlng2.isCheckPoint() ? 1 : 0);
			arrayList2.add(waypoint);
		}
		return arrayList2;
	}

	public static String keyOf(List<WayPoint> pair) {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < pair.size(); i++) {
			WayPoint wayPoint = pair.get(i);
			if (i != 0) {
				sb.append(":");
			}
			sb.append(wayPoint.getLatitude());
			sb.append(",");
			sb.append(wayPoint.getLongitude());
		}
		return sb.toString();
	}

	protected RouteBook afterBuild(RouteBook routeBook, List<String> response) {
		return routeBook;
	}

	protected void beforeBuild(List<List<WayPoint>> points) {
	}

	protected abstract List<IGeoPoint> extractPoints(String responseBody);

	protected abstract boolean isSuccessful(String body);

	protected abstract String requestRouteBook(List<WayPoint> wayPoints) throws IOException;

	@Override public WayPoint getWayPointAt(int index) {
		List<WayPoint> list = this.points;
		if (list == null || index < 0 || index >= list.size()) {
			return null;
		}
		return this.points.get(index);
	}

	@Override public void setWayPointAt(int wayPointAt, WayPoint wayPoint) {
		if (wayPointAt <= this.points.size()) {
			this.points.set(wayPointAt, wayPoint);
		}
	}

	@Override public int indexOf(WayPoint wayPoint) {
		return this.points.indexOf(wayPoint);
	}

	@Override public int getWayPointSize() {
		if (points != null) {
			return points.size();
		}
		return 0;
	}

	@Override public List<WayPoint> getWayPoints() {
		for (int i = 0; i < points.size(); i++) {
			WayPoint item = points.get(i);
			LogUtils.d("AbstractRouteBookSourceModel", "getWayPoints item = " + item + ", i = " + i + "\n");
		}
		return new ArrayList<>(this.points);
	}

	@Override public void removeAllWayPoint() {
		this.points.clear();
	}

	@Override public WayPoint removeAt(int index) {
		if (index < 0 || index >= this.points.size()) {
			return null;
		}
		return this.points.remove(index);
	}

	@Override public void addWayPoints(WayPoint... points) {
		if (points == null || points.length == 0) {
			return;
		}
		this.points.addAll(Arrays.asList(points));
	}

	@Override public void addWayPointsAt(int index, WayPoint... wayPoints) {
		if (wayPoints == null || wayPoints.length == 0) {
			return;
		}
		if (index < 0 || index > this.points.size()) {
			throw new IllegalStateException("Index out of bound");
		}
		this.points.addAll(index, Arrays.asList(wayPoints));
	}

	@Override public List<IGeoPoint> preview() throws IOException, IllegalArgumentException {
		List<WayPoint> wayPoints = getWayPoints();
		ensurePointCount(wayPoints);
		List<List<WayPoint>> segment = segment(wayPoints);
		ArrayList<IGeoPoint> arrayList = new ArrayList<>();
		clearDistance();
		for (List<WayPoint> list : segment) {
			List<IGeoPoint> extractPoints = extractPoints(requestRouteBook(list));
			if (extractPoints != null) {
				arrayList.addAll(extractPoints);
			}
		}
		return arrayList;
	}

	@Override public RouteBook build() throws IOException, IllegalArgumentException {
		List<WayPoint> wayPoints = getWayPoints();
		ensurePointCount(wayPoints);
		boolean z = false;
		// 线路集合
		List<List<WayPoint>> segment = segment(wayPoints);
		ArrayList<BiciLatlng> arrayList = new ArrayList<>();
		for (WayPoint wayPoint : wayPoints) {
			IGeoPoint earth = wayPoint.toEarth(true);
			BiciLatlng biciLatlng = new BiciLatlng(earth.getLatitude(), earth.getLongitude());
			biciLatlng.setAddress(wayPoint.getAddress());
			biciLatlng.setContent(wayPoint.getContent());
			biciLatlng.setImage(wayPoint.getImage());
			if (wayPoint.getWayPointType() == TYPE_CHECK_POINT) {
				z = true;
			}
			biciLatlng.setIsCheckPoint(z);
			biciLatlng.setName(wayPoint.getTitle());
			arrayList.add(biciLatlng);
		}
		beforeBuild(segment);
		RouteBook routeBook = new RouteBook();
		routeBook.setUuid(UUID.randomUUID().toString());
		routeBook.setUserId(SharedManager.getInstance().getUserId());
		routeBook.setServerType(TYPE_SOURCE_CREATE);
		routeBook.setCreateTime(System.currentTimeMillis());
		routeBook.setSport(Workout.TYPE_CYCLING);
		//routeBook.setTitle(LushuTitleUtil.buildLushuDefaultTitle(App.getContext(), routeBook));
		routeBook.setSourceType(this.sourceType);
		routeBook.setStartAddress(wayPoints.get(0).getAddress());
		routeBook.setEndAddress(wayPoints.get(wayPoints.size() - 1).getAddress());
		routeBook.save();
		ArrayList<Waypoint> waypoints = getWaypoints(arrayList, routeBook);
		Waypoint.savePoints(waypoints);
		List<String> response = new ArrayList<>();
		for (List<WayPoint> list : segment) {
			String requestRouteBook = requestRouteBook(list);
			Log.i("AbstractRouteBookSourceModel requestRouteBook = " + requestRouteBook);
			response.add(requestRouteBook);
			try {
				long id = RouteBookUtil.parseDirection(requestRouteBook, arrayList, null, RouteBook.TYPE_BAIDU);
				RouteBook byId = RouteBook.getById(id);
				byId.setUploadEnable(z);
				List<RouteBookPoint> lushuPoints = RouteBookPoint.getByLushuId(id);
				LatLngBounds.Builder builder = new LatLngBounds.Builder();
				for (RouteBookPoint lushuPoint : lushuPoints) {
					builder.include(new LatLng(lushuPoint.getLatitude(), lushuPoint.getLongitude()));
					lushuPoint.setLushuId(routeBook.getId());
				}
				LatLngBounds build = builder.build();
				routeBook.setNortheastLat(build.northeast.latitude);
				routeBook.setNortheastLng(build.northeast.longitude);
				routeBook.setSouthwestLat(build.southwest.latitude);
				routeBook.setSouthwestLng(build.southwest.longitude);
				RouteBookPoint.savePoints(lushuPoints);
				routeBook.setDistance(routeBook.getDistance() + byId.getDistance());
				routeBook.save();
				RouteBookUtil.deleteRouteBook(byId);
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return afterBuild(routeBook, response);
	}

	private @NonNull ArrayList<Waypoint> getWaypoints(ArrayList<BiciLatlng> arrayList, RouteBook routeBook) {
		ArrayList<Waypoint> arrayList2 = new ArrayList<>();
		for (int i2 = 0; i2 < arrayList.size(); i2++) {
			BiciLatlng biciLatlng = arrayList.get(i2);
			Waypoint waypoint = new Waypoint();
			waypoint.setLushuId(routeBook.getId());
			waypoint.setLatitude(biciLatlng.getLatitude());
			waypoint.setLongitude(biciLatlng.getLongitude());
			waypoint.setTitle(biciLatlng.getName());
			waypoint.setContent(biciLatlng.getContent());
			waypoint.setImage(biciLatlng.getImage());
			waypoint.setType(biciLatlng.isCheckPoint() ? 1 : 0);
			arrayList2.add(waypoint);
		}
		return arrayList2;
	}

	@Override public RouteBook reBuild(RouteBook routeBook) throws IOException, IllegalArgumentException {
		List<WayPoint> wayPoints = getWayPoints();
		ensurePointCount(wayPoints);
		List<List<WayPoint>> segment = segment(wayPoints);
		ArrayList<BiciLatlng> arrayList = new ArrayList<>();
		for (WayPoint wayPoint : wayPoints) {
			boolean z = false;
			IGeoPoint earth = wayPoint.toEarth(true);
			BiciLatlng biciLatlng = new BiciLatlng(earth.getLatitude(), earth.getLongitude());
			biciLatlng.setAddress(wayPoint.getAddress());
			biciLatlng.setContent(wayPoint.getContent());
			biciLatlng.setImage(wayPoint.getImage());
			if (wayPoint.getWayPointType() == 4) {
				z = true;
			}
			biciLatlng.setIsCheckPoint(z);
			biciLatlng.setName(wayPoint.getTitle());
			arrayList.add(biciLatlng);
		}
		beforeBuild(segment);
		routeBook.setDistance(Utils.DOUBLE_EPSILON);
		Waypoint.deleteByRouteBookId(routeBook.getId());
		RouteBookPoint.deleteByRouteBookId(routeBook.getId());
		ArrayList<Waypoint> arrayList2 = getWaypoints(routeBook, arrayList);
		Waypoint.savePoints(arrayList2);
		ArrayList<String> response = new ArrayList<>();
		for (List<WayPoint> list : segment) {
			String requestRouteBook = requestRouteBook(list);
			response.add(requestRouteBook);
			try {
				long parseDirection = RouteBookUtil.parseDirection(requestRouteBook, arrayList, null, 3);
				RouteBook byId = RouteBook.getById(parseDirection);
				byId.setUploadEnable(false);
				List<RouteBookPoint> byLushuId = RouteBookPoint.getByLushuId(parseDirection);
				LatLngBounds.Builder builder = new LatLngBounds.Builder();
				for (RouteBookPoint lushuPoint : byLushuId) {
					builder.include(new LatLng(lushuPoint.getLatitude(), lushuPoint.getLongitude()));
					lushuPoint.setLushuId(routeBook.getId());
				}
				LatLngBounds build = builder.build();
				routeBook.setNortheastLat(build.northeast.latitude);
				routeBook.setNortheastLng(build.northeast.longitude);
				routeBook.setSouthwestLat(build.southwest.latitude);
				routeBook.setSouthwestLng(build.southwest.longitude);
				RouteBookPoint.savePoints(byLushuId);
				routeBook.setDistance(routeBook.getDistance() + byId.getDistance());
				RouteBookUtil.deleteRouteBook(byId);
				routeBook.save();
			} catch (JSONException e) {
				e.printStackTrace();
			}
		}
		return afterBuild(routeBook, response);
	}

	public RouteBookCacheStrategy getCacheStrategy() {
		return this.cacheStrategy;
	}

	public void setCacheStrategy(RouteBookCacheStrategy cacheStrategy) {
		this.cacheStrategy = cacheStrategy;
	}

	@Override public double getDistance() {
		return this.distance;
	}

	public void plusDistance(double dist) {
		this.distance += dist;
	}

	public void clearDistance() {
		this.distance = Utils.DOUBLE_EPSILON;
	}

	@Override public void release() {
		this.points.clear();
		this.cacheStrategy.release();
		this.cacheStrategy = null;
	}

	private void ensurePointCount(List<WayPoint> pointList) {
		if (pointList.size() < 2) {
			throw new IllegalArgumentException("Point must be greater than two");
		}
	}

	protected List<List<WayPoint>> segment(List<WayPoint> wayPoints) {
		ArrayList<List<WayPoint>> arrayList = new ArrayList<>();
		int i = 0;
		while (i < wayPoints.size() - 1) {
			i++;
			arrayList.add(Arrays.asList(wayPoints.get(i - 1), wayPoints.get(i)));
		}
		return arrayList;
	}
}
